#include "udpsocket.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

using namespace VLRTSP;


/**
 * @Author: CimZzz
 * @Date: 2022-01-14 16:35:10
 * 
 * 构造函数
 */
UDPSocket::UDPSocket() {
	this->fd = 0;
	this->port = 0;
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-14 16:35:24
 * 
 * 析构函数
 */
UDPSocket::~UDPSocket() {
	this->close();
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-14 16:36:27
 * 
 * 绑定地址 & 端口
 * @return 如果绑定成功返回 true
 */
bool UDPSocket::bind(uint16_t port) {
	if(this->fd > 0) {
		this->close();
	}

	this->fd = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	struct sockaddr_in addr = {0};			  
    addr.sin_family = AF_INET;		  
    addr.sin_addr.s_addr = inet_addr("0.0.0.0"); 
    addr.sin_port = htons(port);  
    if(::bind(this->fd, (struct sockaddr*)&addr, sizeof addr) == -1) {      
		this->close();
        return false;
    }
	this->port = port;
    return true;
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-10 16:21:42
 * 
 * 读取套接字中的字节
 * @param buffer 接收读取的字节缓冲区
 * @param size 指定读取的字节长度，0 表示读取任意长度
 * @return 读取成功返回读取长度，-1 表示读取失败
 */
int64_t UDPSocket::read(Buffer* buffer, uint32_t size) {
	if(fd > 0 && buffer != nullptr) {
		if(size > 0) {
			uint8_t readBuffer[size];
			uint32_t needReadSize = size;
			int64_t totalSize = 0;
			int64_t readSize = 0;

			READ:
			readSize = ::read(fd, readBuffer + totalSize, needReadSize);
			if(readSize <= 0) {
				return -1;
			}

			totalSize += readSize;
			needReadSize -= readSize;
			if(needReadSize < 0) {
				return -1;
			}

			if(readSize == 0 || needReadSize == 0) {
				buffer->appendBuffer(readBuffer, 0, size);
				return totalSize;
			}
			goto READ;	
		} else {
			uint8_t readBuffer[255];
			int64_t readSize = ::read(fd, readBuffer, 255);
			if(readSize <= 0) {
				return -1;
			}
			buffer->appendBuffer(readBuffer, 0, readSize);
			return readSize;
		}
	}
	else {
		return -1;
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-10 16:46:19
 * 
 * 写字节缓冲区中的字节
 * @param buffer 字节缓冲区
 * @param ip IP 地址
 * @param port 端口号
 * @return 如果写入成功返回 true
 */
bool UDPSocket::write(Buffer* buffer, std::string ip, uint16_t port) {
	if(this->fd > 0) {
		struct sockaddr_in addr = {0};			  
		addr.sin_family = AF_INET;		  
		addr.sin_addr.s_addr = inet_addr(ip.c_str()); 
		addr.sin_port = htons(port);  
		int ret = ::sendto(this->fd, buffer->getBuffer(), buffer->getBufferLength(), 0, (struct sockaddr *)&addr, sizeof(addr));
		return ret != -1;
	}
	return false;
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-14 16:37:08
 * 
 * 关闭套接字
 */
void UDPSocket::close() {
	if(this->fd > 0) {
		::close(this->fd);
		this->fd = 0;
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-11 15:37:17
 * 
 * 获取 Socket Id
 */
VL_SOCKET UDPSocket::getSocketId() {
	return this->fd;
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-14 16:59:00
 * 
 * 获取绑定的端口号
 * @return 绑定的端口号
 */
uint16_t UDPSocket::getBindPort() {
	return this->port;
}